<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">

<head>
    <!-- Book generated using mdBook -->
    <meta charset="UTF-8">
    <title>grep - exercisms.io 快速练习</title>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
    <meta name="description" content="exercisms 的练习，网页版.">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="theme-color" content="#ffffff" />

    <link rel="shortcut icon" href="../favicon.png">
    <link rel="stylesheet" href="../css/variables.css">
    <link rel="stylesheet" href="../css/general.css">
    <link rel="stylesheet" href="../css/chrome.css">
    <link rel="stylesheet" href="../css/print.css" media="print">

    <!-- Fonts -->
    <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
    <link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800"
        rel="stylesheet" type="text/css">
    <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">

    <!-- Highlight.js Stylesheets -->
    <link rel="stylesheet" href="../highlight.css">
    <link rel="stylesheet" href="../tomorrow-night.css">
    <link rel="stylesheet" href="../ayu-highlight.css">

    <!-- Custom theme stylesheets -->
    
    <link rel="stylesheet" href="../theme/custom.css">
    

    
</head>

<body class="light">
    <!-- Provide site root to javascript -->
    <script type="text/javascript">var path_to_root = "../";</script>

    <!-- Work around some values being stored in localStorage wrapped in quotes -->
    <script type="text/javascript">
        try {
            var theme = localStorage.getItem('mdbook-theme');
            var sidebar = localStorage.getItem('mdbook-sidebar');

            if (theme.startsWith('"') && theme.endsWith('"')) {
                localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
            }

            if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
            }
        } catch (e) { }
    </script>

    <!-- Set the theme before any content is loaded, prevents flash -->
    <script type="text/javascript">
        var theme;
        try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
        if (theme === null || theme === undefined) { theme = 'light'; }
        document.body.className = theme;
        document.querySelector('html').className = theme + ' js';
    </script>

    <!-- Hide / unhide sidebar before it is displayed -->
    <script type="text/javascript">
        var html = document.querySelector('html');
        var sidebar = 'hidden';
        if (document.body.clientWidth >= 1080) {
            try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch (e) { }
            sidebar = sidebar || 'visible';
        }
        html.classList.remove('sidebar-visible');
        html.classList.add("sidebar-" + sidebar);
    </script>

    <nav id="sidebar" class="sidebar" aria-label="Table of contents">
        <ol class="chapter"><li><a href="../index.html"><strong aria-hidden="true">1.</strong> 超过 88 道练习，任点</a></li><li><a href="../low.html"><strong aria-hidden="true">2.</strong> 易</a></li><li><ol class="section"><li><a href="../hello-world/README.zh.html"><strong aria-hidden="true">2.1.</strong> hello world</a></li><li><a href="../gigasecond/README.zh.html"><strong aria-hidden="true">2.2.</strong> 千兆秒 &gt;&lt; Gigasecond)</a></li><li><a href="../leap/README.zh.html"><strong aria-hidden="true">2.3.</strong> 闰年 &gt;&lt; Leap</a></li><li><a href="../raindrops/README.zh.html"><strong aria-hidden="true">2.4.</strong> 雨滴声 &gt;&lt; Raindrops</a></li><li><a href="../reverse-string/README.zh.html"><strong aria-hidden="true">2.5.</strong> 反转字符串 &gt;&lt; Reverse String</a></li><li><a href="../nth-prime/README.zh.html"><strong aria-hidden="true">2.6.</strong> 第 n 个素数 &gt;&lt; Nth Prime</a></li><li><a href="../bob/README.zh.html"><strong aria-hidden="true">2.7.</strong> 迟钝孩子 &gt;&lt; Bob</a></li><li><a href="../beer-song/README.zh.html"><strong aria-hidden="true">2.8.</strong> 啤酒之歌 &gt;&lt; Beer Song</a></li><li><a href="../proverb/README.zh.html"><strong aria-hidden="true">2.9.</strong> 谚语串烧 &gt;&lt; Proverb</a></li><li><a href="../difference-of-squares/README.zh.html"><strong aria-hidden="true">2.10.</strong> 平方差 &gt;&lt; Difference Of Squares</a></li><li><a href="../sum-of-multiples/README.zh.html"><strong aria-hidden="true">2.11.</strong> 倍数之和 &gt;&lt; Sum Of Multiples</a></li><li><a href="../grains/README.zh.html"><strong aria-hidden="true">2.12.</strong> 谷物 &gt;&lt; Grains</a></li><li><a href="../pythagorean-triplet/README.zh.html"><strong aria-hidden="true">2.13.</strong> 勾股数 &gt;&lt; Pythagorean Triplet</a></li><li><a href="../prime-factors/README.zh.html"><strong aria-hidden="true">2.14.</strong> 素数因子 &gt;&lt; Prime Factors</a></li><li><a href="../series/README.zh.html"><strong aria-hidden="true">2.15.</strong> 子串 &gt;&lt; Series</a></li><li><a href="../armstrong-numbers/README.zh.html"><strong aria-hidden="true">2.16.</strong> 水仙花数 &gt;&lt; Armstrong Numbers</a></li><li><a href="../collatz-conjecture/README.zh.html"><strong aria-hidden="true">2.17.</strong> 3n+1 猜想 &gt;&lt; Collatz Conjecture</a></li><li><a href="../diffie-hellman/README.zh.html"><strong aria-hidden="true">2.18.</strong> 迪菲-赫尔曼密钥交换 &gt;&lt; Diffie Hellman</a></li></ol></li><li><a href="../medium.html"><strong aria-hidden="true">3.</strong> 中等</a></li><li><ol class="section"><li><a href="../saddle-points/README.zh.html"><strong aria-hidden="true">3.1.</strong> 鞍点 &gt;&lt; Saddle Points</a></li><li><a href="../isogram/README.zh.html"><strong aria-hidden="true">3.2.</strong> 等值线 &gt;&lt; Isogram</a></li><li><a href="../say/README.zh.html"><strong aria-hidden="true">3.3.</strong> 英文说数字 &gt;&lt; Say</a></li><li><a href="../run-length-encoding/README.zh.html"><strong aria-hidden="true">3.4.</strong> 游程编码 &gt;&lt; Run Length Encoding</a></li><li><a href="../isbn-verifier/README.zh.html"><strong aria-hidden="true">3.5.</strong> 图书编号 &gt;&lt; ISBN Verifier</a></li><li><a href="../perfect-numbers/README.zh.html"><strong aria-hidden="true">3.6.</strong> 数字也能分类 &gt;&lt; Perfect Numbers</a></li><li><a href="../clock/README.zh.html"><strong aria-hidden="true">3.7.</strong> 时钟 &gt;&lt; Clock</a></li><li><a href="../dot-dsl/README.zh.html"><strong aria-hidden="true">3.8.</strong> DOT DSL</a></li><li><a href="../hamming/README.zh.html"><strong aria-hidden="true">3.9.</strong> 汉明距离 &gt;&lt; Hamming</a></li><li><a href="../simple-linked-list/README.zh.html"><strong aria-hidden="true">3.10.</strong> 简单链表 &gt;&lt; Simple Linked List</a></li><li><a href="../pascals-triangle/README.zh.html"><strong aria-hidden="true">3.11.</strong> 杨辉三角形 &gt;&lt; Pascal's Triangle</a></li><li><a href="../scrabble-score/README.zh.html"><strong aria-hidden="true">3.12.</strong> 字母的分数游戏 &gt;&lt; Scrabble Score</a></li><li><a href="../pangram/README.zh.html"><strong aria-hidden="true">3.13.</strong> 全字母句 &gt;&lt; Pangram</a></li><li><a href="../paasio/README.zh.html"><strong aria-hidden="true">3.14.</strong> PaaS-IO-报告 &gt;&lt; Paasio</a></li><li><a href="../nucleotide-count/README.zh.html"><strong aria-hidden="true">3.15.</strong> 核苷酸计数 &gt;&lt; Nucleotide Count</a></li><li><a href="../luhn/README.zh.html"><strong aria-hidden="true">3.16.</strong> 模 10 算法 &gt;&lt; Luhn</a></li><li><a href="../largest-series-product/README.zh.html"><strong aria-hidden="true">3.17.</strong> 最大数字子串乘积 &gt;&lt; Largest Series Product</a></li><li><a href="../word-count/README.zh.html"><strong aria-hidden="true">3.18.</strong> 单词计数 &gt;&lt; Word Count</a></li><li><a href="../atbash-cipher/README.zh.html"><strong aria-hidden="true">3.19.</strong> Atbash 加密 &gt;&lt; Atbash Cipher</a></li><li><a href="../crypto-square/README.zh.html"><strong aria-hidden="true">3.20.</strong> 密码矩形 &gt;&lt; Crypto Square</a></li><li><a href="../rotational-cipher/README.zh.html"><strong aria-hidden="true">3.21.</strong> 旋转密码 &gt;&lt; Rotational Cipher</a></li><li><a href="../simple-cipher/README.zh.html"><strong aria-hidden="true">3.22.</strong> 简单加密 &gt;&lt; Simple Cipher</a></li><li><a href="../rail-fence-cipher/README.zh.html"><strong aria-hidden="true">3.23.</strong> 栅栏密码 &gt;&lt; Rail Fence Cipher</a></li><li><a href="../etl/README.zh.html"><strong aria-hidden="true">3.24.</strong> ETL</a></li><li><a href="../accumulate/README.zh.html"><strong aria-hidden="true">3.25.</strong> 集合操作 &gt;&lt; Accumulate</a></li><li><a href="../acronym/README.zh.html"><strong aria-hidden="true">3.26.</strong> 术语 &gt;&lt; Acronym</a></li><li><a href="../sieve/README.zh.html"><strong aria-hidden="true">3.27.</strong> 素数筛 &gt;&lt; Sieve</a></li><li><a href="../rna-transcription/README.zh.html"><strong aria-hidden="true">3.28.</strong> RNA 转录 &gt;&lt; RNA Transcription</a></li><li><a href="../triangle/README.zh.html"><strong aria-hidden="true">3.29.</strong> 三角形</a></li><li><a href="../roman-numerals/README.zh.html"><strong aria-hidden="true">3.30.</strong> 罗马数字 &gt;&lt; Roman Numerals</a></li><li><a href="../all-your-base/README.zh.html"><strong aria-hidden="true">3.31.</strong> 你所的基本</a></li><li><a href="../grade-school/README.zh.html"><strong aria-hidden="true">3.32.</strong> 学册</a></li><li><a href="../binary-search/README.zh.html"><strong aria-hidden="true">3.33.</strong> 二分查找</a></li><li><a href="../robot-simulator/README.zh.html"><strong aria-hidden="true">3.34.</strong> 机器人模拟器</a></li><li><a href="../bracket-push/README.zh.html"><strong aria-hidden="true">3.35.</strong> 括号配套</a></li><li><a href="../luhn-from/README.zh.html"><strong aria-hidden="true">3.36.</strong> Luhn From</a></li><li><a href="../queen-attack/README.zh.html"><strong aria-hidden="true">3.37.</strong> 皇后 攻击</a></li><li><a href="../bowling/README.zh.html"><strong aria-hidden="true">3.38.</strong> 保龄球</a></li><li><a href="../sublist/README.zh.html"><strong aria-hidden="true">3.39.</strong> 子列表</a></li><li><a href="../space-age/README.zh.html"><strong aria-hidden="true">3.40.</strong> 地球年</a></li><li><a href="../luhn-trait/README.zh.html"><strong aria-hidden="true">3.41.</strong> Luhn Trait</a></li><li><a href="../macros/README.zh.html"><strong aria-hidden="true">3.42.</strong> 宏</a></li><li><a href="../allergies/README.zh.html"><strong aria-hidden="true">3.43.</strong> 过敏</a></li><li><a href="../variable-length-quantity/README.zh.html"><strong aria-hidden="true">3.44.</strong> 可变长度数量</a></li><li><a href="../phone-number/README.zh.html"><strong aria-hidden="true">3.45.</strong> 电话号码</a></li><li><a href="../wordy/README.zh.html"><strong aria-hidden="true">3.46.</strong> 罗唆</a></li><li><a href="../tournament/README.zh.html"><strong aria-hidden="true">3.47.</strong> 比赛</a></li><li><a href="../custom-set/README.zh.html"><strong aria-hidden="true">3.48.</strong> 自定义 set</a></li><li><a href="../alphametics/README.zh.html"><strong aria-hidden="true">3.49.</strong> 字母谜题</a></li><li><a href="../two-bucket/README.zh.html"><strong aria-hidden="true">3.50.</strong> 两个桶</a></li><li><a href="../pig-latin/README.zh.html"><strong aria-hidden="true">3.51.</strong> 猪的拉丁文</a></li><li><a href="../diamond/README.zh.html"><strong aria-hidden="true">3.52.</strong> 钻石</a></li><li><a href="../spiral-matrix/README.zh.html"><strong aria-hidden="true">3.53.</strong> 螺旋矩阵</a></li><li><a href="../palindrome-products/README.zh.html"><strong aria-hidden="true">3.54.</strong> 回文产品</a></li><li><a href="../poker/README.zh.html"><strong aria-hidden="true">3.55.</strong> 扑克</a></li><li><a href="../grep/README.zh.html" class="active"><strong aria-hidden="true">3.56.</strong> grep</a></li><li><a href="../scale-generator/README.zh.html"><strong aria-hidden="true">3.57.</strong> 音阶生成器</a></li><li><a href="../decimal/README.zh.html"><strong aria-hidden="true">3.58.</strong> 十进制</a></li><li><a href="../anagram/README.zh.html"><strong aria-hidden="true">3.59.</strong> 字谜</a></li><li><a href="../protein-translation/README.zh.html"><strong aria-hidden="true">3.60.</strong> 蛋白质翻译</a></li><li><a href="../robot-name/README.zh.html"><strong aria-hidden="true">3.61.</strong> 机器人名称</a></li><li><a href="../book-store/README.zh.html"><strong aria-hidden="true">3.62.</strong> 书店</a></li></ol></li><li><a href="../high.html"><strong aria-hidden="true">4.</strong> 难</a></li><li><ol class="section"><li><a href="../ocr-numbers/README.zh.html"><strong aria-hidden="true">4.1.</strong> OCR 号码</a></li><li><a href="../minesweeper/README.zh.html"><strong aria-hidden="true">4.2.</strong> 扫雷</a></li><li><a href="../dominoes/README.zh.html"><strong aria-hidden="true">4.3.</strong> 骨牌</a></li><li><a href="../parallel-letter-frequency/README.zh.html"><strong aria-hidden="true">4.4.</strong> 并行字母频率</a></li><li><a href="../rectangles/README.zh.html"><strong aria-hidden="true">4.5.</strong> 矩形</a></li><li><a href="../forth/README.zh.html"><strong aria-hidden="true">4.6.</strong> Forth</a></li><li><a href="../circular-buffer/README.zh.html"><strong aria-hidden="true">4.7.</strong> 循环缓冲区</a></li><li><a href="../react/README.zh.html"><strong aria-hidden="true">4.8.</strong> React</a></li></ol></li><li><a href="../untag.html"><strong aria-hidden="true">5.</strong> 未标签</a></li><li><ol class="section"><li><a href="../hexadecimal/README.zh.html"><strong aria-hidden="true">5.1.</strong> 十六进制</a></li><li><a href="../nucleotide-codons/README.zh.html"><strong aria-hidden="true">5.2.</strong> 核苷酸密码子</a></li><li><a href="../two-fer/README.zh.html"><strong aria-hidden="true">5.3.</strong> two-fer</a></li><li class="spacer"></li></ol></li><li><a href="../add-test-code.html">修改 mdBook 主题</a></li></ol>
    </nav>

    <div id="page-wrapper" class="page-wrapper">

        <div class="page">
            
            <div id="menu-bar" class="menu-bar">
                <div id="menu-bar-sticky-container">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents"
                            aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <!-- START - Rust Cookbook customization -->
                        <button id="edit-button" class="icon-button" type="button" title="Fork and edit" aria-label="Fork and edit"
                            aria-haspopup="true" aria-expanded="false" aria-controls="edit">
                            <i class="fa fa-edit">Edit</i>
                        </button>
                        <!-- END - Rust Cookbook customization -->
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme"
                            aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light <span class="default">(default)</span></button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)"
                            aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                        
                    </div>

                    <h1 class="menu-title">exercisms.io 快速练习</h1>
                    
                        <div class="right-buttons">
                            <a href="../print.html" title="Print this book" aria-label="Print this book">
                                <i id="print-button" class="fa fa-print"></i>
                            </a>
                            
                        </div>
                    </div>
                </div>

            
            <div id="search-wrapper" class="hidden">
                <form id="searchbar-outer" class="searchbar-outer">
                    <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..."
                        aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                </form>
                <div id="searchresults-outer" class="searchresults-outer hidden">
                    <div id="searchresults-header" class="searchresults-header"></div>
                    <ul id="searchresults">
                    </ul>
                </div>
            </div>
            

            <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
            <script type="text/javascript">
                document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                Array.from(document.querySelectorAll('#sidebar a')).forEach(function (link) {
                    link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                });
            </script>

            <!-- // START - Rust Cookbook customization -->
            <script>
                document.getElementById("edit-button").addEventListener("click", function () {
                    var editWindow = window.open("https://github.com/chinanf-boy/exercism-rust-zh/edit/master/src/grep/README.zh.md");
                });</script>
            <!-- // END - Rust Cookbook customization -->

            <div id="content" class="content">
                <main>
                    <a class="header" href="#grep" id="grep"><h1>Grep</h1></a>
<a class="header" href="#1-readme" id="1-readme"><h2>1. Readme</h2></a>
<a class="header" href="#grep-1" id="grep-1"><h1>grep</h1></a>
<p>在文件中，搜索与正则表达式模式匹配的行。返回每个匹配行的行号和内容.</p>
<p>Unix<a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html"><code>grep</code></a>命令可用于搜索，与用户提供的搜索查询匹配的一个或多个文件中的行(称为<em>模式</em>).</p>
<p>该<code>grep</code>命令有三个参数:</p>
<ol>
<li>用于匹配文件中的行的模式.</li>
<li>零个或多个标志以自定义匹配行为.</li>
<li>一个或多个要搜索匹配行的文件.</li>
</ol>
<p>你的任务是实现<code>grep</code>函数，应该读取指定文件的内容，找到与指定模式匹配的行，然后将这些行输出为单个字符串。请注意，行应按其找到的顺序输出，第一个文件中的第一个匹配行首先输出。</p>
<p>例如，假设有一个名为”input.txt”的文件，其中包含以下内容:</p>
<pre><code class="language-text">hello
world
hello again
</code></pre>
<p>如果我们打电话<code>grep &quot;hello&quot; input.txt</code>，返回的字符串应该是:</p>
<pre><code class="language-text">hello
hello again
</code></pre>
<a class="header" href="#旗" id="旗"><h3>旗</h3></a>
<p>如前所述，<code>grep</code>命令还应该支持以下标志:</p>
<ul>
<li><code>-n</code>打印每个匹配行的行号.</li>
<li><code>-l</code>仅打印包含至少一个匹配行的文件的名称.</li>
<li><code>-i</code>使用不区分大小写的比较匹配行.</li>
<li><code>-v</code>反转程序 - 收集所有与模式不匹配的行.</li>
<li><code>-x</code>仅匹配整行，而不是匹配包含匹配的行.</li>
</ul>
<p>如果我们运行<code>grep -n &quot;hello&quot; input.txt</code>，<code>-n</code>flag 将要求匹配的行以其行号作为前缀:</p>
<pre><code class="language-text">1:hello
3:hello again
</code></pre>
<p>如果我们运行<code>grep -i &quot;HELLO&quot; input.txt</code>，我们将做一个不区分大小写的匹配，输出将是:</p>
<pre><code class="language-text">hello
hello again
</code></pre>
<p>该<code>grep</code>命令应该一次支持多个标志.</p>
<p>例如，运行<code>grep -l -v &quot;hello&quot; file1.txt file2.txt</code>应该打印不包含字符串”hello”的文件的名称.</p>
<a class="header" href="#错误处理" id="错误处理"><h3>错误处理</h3></a>
<p>本练习介绍了该用法<code>failure</code>箱子，它为您提供了管理自定义错误类型的方法。要了解有关箱子的更多信息，请参阅<a href="https://boats.gitlab.io/failure/intro.html">failure 文档</a></p>
<a class="header" href="#补充阅读" id="补充阅读"><h3>补充阅读</h3></a>
<p>虽然本练习要求您只实现最基本的<code>grep</code>函数，实际上是有一个完全的，重新实现的<code>grep</code>Rust 项目 -<a href="https://github.com/BurntSushi/ripgrep">ripgrep</a>.</p>
<p>如果您喜欢在 Rust 中，重写基本工具程序的概念，请务必检查以下项目:</p>
<ul>
<li><a href="https://github.com/sharkdp/fd">fd</a>- 复刻<code>find</code></li>
<li><a href="https://github.com/ogham/exa">exa</a>- 复刻<code>ls</code></li>
<li><a href="https://github.com/sharkdp/bat">bat</a>- 复刻<code>cat</code></li>
<li><a href="https://github.com/uutils/coreutils">coreutils</a>- 重写 GNU coreutils</li>
</ul>
<a class="header" href="#资源" id="资源"><h2>资源</h2></a>
<p>与 Nate Foster 的对话.<a href="http://www.cs.cornell.edu/Courses/cs3110/2014sp/hw/0/ps0.pdf">http://www.cs.cornell.edu/Courses/cs3110/2014sp/hw/0/ps0.pdf</a></p>
<a class="header" href="#2-开始你的表演" id="2-开始你的表演"><h2>2. 开始你的表演</h2></a>
<pre><pre class="playpen"><code class="language-rust editable">extern crate failure;

use failure::Error;

/// While using raw slice of str to handle flags is convenient,
/// in the real-world projects it is customary to use a struct,
/// that contains flags-related logic. So in this exercise
/// we ask you to implement a custom struct.
///
/// If you are curious about real-world implementation, refer to the `clap-rs` crate:
/// https://github.com/kbknapp/clap-rs/blob/master/src/args/arg_matches.rs
#[derive(Debug)]
pub struct Flags;

impl Flags {
   pub fn new(flags: &amp;[&amp;str]) -&gt; Self {
       unimplemented!(
           &quot;Given the flags {:?} implement your own 'Flags' struct to handle flags-related logic&quot;,
           flags
       );
   }
}

pub fn grep(pattern: &amp;str, flags: &amp;Flags, files: &amp;[&amp;str]) -&gt; Result&lt;Vec&lt;String&gt;, Error&gt; {
   unimplemented!(
       &quot;Search the files '{:?}' for '{}' pattern and save the matches in a vector. Your search logic should be aware of the given flags '{:?}'&quot;,
       files,
       pattern,
       flags
   );
}

</code></pre></pre>
<a class="header" href="#3-测试代码查看" id="3-测试代码查看"><h2>3. 测试代码查看</h2></a>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
use std::fs;

static ILIAD_CONTENT: &amp;'static str = &quot;Achilles sing, O Goddess! Peleus' son;
His wrath pernicious, who ten thousand woes
Caused to Achaia's host, sent many a soul
Illustrious into Ades premature,
And Heroes gave (so stood the will of Jove)
To dogs and to all ravening fowls a prey,
When fierce dispute had separated once
The noble Chief Achilles from the son
Of Atreus, Agamemnon, King of men.
&quot;;

static MIDSUMMER_NIGHT_CONTENT: &amp;'static str = &quot;I do entreat your grace to pardon me.
I know not by what power I am made bold,
Nor how it may concern my modesty,
In such a presence here to plead my thoughts;
But I beseech your grace that I may know
The worst that may befall me in this case,
If I refuse to wed Demetrius.
&quot;;

static PARADISE_LOST_CONTENT: &amp;'static str = &quot;Of Mans First Disobedience, and the Fruit
Of that Forbidden Tree, whose mortal tast
Brought Death into the World, and all our woe,
With loss of Eden, till one greater Man
Restore us, and regain the blissful Seat,
Sing Heav'nly Muse, that on the secret top
Of Oreb, or of Sinai, didst inspire
That Shepherd, who first taught the chosen Seed
&quot;;

/// In The White Night
/// A poem by Alexander Blok(https://en.wikipedia.org/wiki/Alexander_Blok)
/// a Russian poet who is regarded as one of the most important figures of the Silver Age of Russian Poetry
/// You can read the translation here: https://lyricstranslate.com/ru/белой-ночью-месяц-красный-white-night-crimson-crescent.html
static IN_THE_WHITE_NIGHT_CONTENT: &amp;'static str = &quot;Белой ночью месяц красный
Выплывает в синеве.
Бродит призрачно-прекрасный,
Отражается в Неве.
Мне провидится и снится
Исполпенье тайных дум.
В вас ли доброе таится,
Красный месяц, тихий шум?..
&quot;;

struct Fixture&lt;'a&gt; {
   file_names: &amp;'a [&amp;'a str],
}

impl&lt;'a&gt; Fixture&lt;'a&gt; {
   fn new(file_names: &amp;'a [&amp;'a str]) -&gt; Self {
       Fixture { file_names }
   }

   fn set_up(&amp;self) {
       let file_name_content_pairs = self
           .file_names
           .iter()
           .cloned()
           .map(|file_name| {
               if file_name.ends_with(&quot;iliad.txt&quot;) {
                   (file_name, ILIAD_CONTENT)
               } else if file_name.ends_with(&quot;midsummer_night.txt&quot;) {
                   (file_name, MIDSUMMER_NIGHT_CONTENT)
               } else if file_name.ends_with(&quot;paradise_lost.txt&quot;) {
                   (file_name, PARADISE_LOST_CONTENT)
               } else {
                   (file_name, IN_THE_WHITE_NIGHT_CONTENT)
               }
           })
           .collect::&lt;Vec&lt;(&amp;str, &amp;str)&gt;&gt;();

       set_up_files(&amp;file_name_content_pairs);
   }
}

impl&lt;'a&gt; Drop for Fixture&lt;'a&gt; {
   fn drop(&amp;mut self) {
       tear_down_files(self.file_names);
   }
}

fn set_up_files(files: &amp;[(&amp;str, &amp;str)]) {
   for (file_name, file_content) in files {
       fs::write(file_name, file_content).expect(&amp;format!(
           &quot;Error setting up file '{}' with the following content:\n{}&quot;,
           file_name, file_content
       ));
   }
}

fn tear_down_files(files: &amp;[&amp;str]) {
   for file_name in files {
       fs::remove_file(file_name).expect(&amp;format!(&quot;Could not delete file '{}'&quot;, file_name));
   }
}

/// This macro is here so that every test case had its own set of files to be used in test.
/// The approach is to create required files for every test case and to append test name to the
/// file names (so for test with a name 'test_one_file_one_match_no_flags' and a required file
/// 'iliad.txt' there would be created a file with a name
/// 'test_one_file_one_match_no_flags_iliad.txt').
/// This allows us to create files for every test case with no intersection between them.
///
/// A better way would be to create required set of files at the start of tests run and to
/// delete them after every test is finished, but there is no trivial way to create such
/// a test fixture in standard Rust, and Exercism restricts the usage of external dependencies
/// in test files. Therefore the above approach is chosen.
///
/// If you have an idea about a better way to implement test fixture for this exercise,
/// please submit PR to the Rust Exercism track: https://github.com/exercism/rust
macro_rules! set_up_test_case {
   ($(#[$flag:meta])+ $test_case_name:ident(pattern=$pattern:expr, flags=[$($grep_flag:expr),*], files=[$($file:expr),+], expected=[$($expected:expr),*])) =&gt; {
       $(#[$flag])+
       fn $test_case_name() {
           let pattern = $pattern;

           let flags = vec![$($grep_flag),*];

           let files = vec![$(concat!(stringify!($test_case_name), &quot;_&quot; , $file)),+];

           let expected = vec![$($expected),*];

           process_grep_case(&amp;pattern, &amp;flags, &amp;files, &amp;expected);
       }
   };
   ($(#[$flag:meta])+ $test_case_name:ident(pattern=$pattern:expr, flags=[$($grep_flag:expr),*], files=[$($file:expr),+], prefix_expected=[$($expected:expr),*])) =&gt; {
       $(#[$flag])+
       fn $test_case_name() {
           let pattern = $pattern;

           let flags = vec![$($grep_flag),*];

           let files = vec![$(concat!(stringify!($test_case_name), &quot;_&quot; , $file)),+];

           let expected = vec![$(concat!(stringify!($test_case_name), &quot;_&quot;, $expected)),*];

           process_grep_case(&amp;pattern, &amp;flags, &amp;files, &amp;expected);
       }

   }
}

fn process_grep_case(pattern: &amp;str, flags: &amp;[&amp;str], files: &amp;[&amp;str], expected: &amp;[&amp;str]) {
   let test_fixture = Fixture::new(files);

   test_fixture.set_up();

   let flags = Flags::new(flags);

   let grep_result = grep(pattern, &amp;flags, files).unwrap();

   assert_eq!(grep_result, expected);
}

// Test returning a Result

#[test]
fn test_nonexistent_file_returns_error() {
   let pattern = &quot;Agamemnon&quot;;

   let flags = Flags::new(&amp;vec![]);

   let files = vec![&quot;test_nonexistent_file_returns_error_iliad.txt&quot;];

   assert!(grep(&amp;pattern, &amp;flags, &amp;files).is_err());
}

#[test]
//#[ignore]
fn test_grep_returns_result() {
   let pattern = &quot;Agamemnon&quot;;

   let flags = Flags::new(&amp;vec![]);

   let files = vec![&quot;test_grep_returns_result_iliad.txt&quot;];

   let test_fixture = Fixture::new(&amp;files);

   test_fixture.set_up();

   assert!(grep(&amp;pattern, &amp;flags, &amp;files).is_ok());
}

// Test grepping a single file

set_up_test_case!(#[test]
//#[ignore]
test_one_file_one_match_no_flags(
   pattern = &quot;Agamemnon&quot;,
   flags = [],
   files = [&quot;iliad.txt&quot;],
   expected = [&quot;Of Atreus, Agamemnon, King of men.&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_one_match_print_line_numbers_flag(
   pattern = &quot;Forbidden&quot;,
   flags = [&quot;-n&quot;],
   files = [&quot;paradise_lost.txt&quot;],
   expected = [&quot;2:Of that Forbidden Tree, whose mortal tast&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_one_match_caseinsensitive_flag(
   pattern = &quot;FORBIDDEN&quot;,
   flags = [&quot;-i&quot;],
   files = [&quot;paradise_lost.txt&quot;],
   expected = [&quot;Of that Forbidden Tree, whose mortal tast&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_one_match_print_file_names_flag(
   pattern = &quot;Forbidden&quot;,
   flags = [&quot;-l&quot;],
   files = [&quot;paradise_lost.txt&quot;],
   prefix_expected = [&quot;paradise_lost.txt&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_one_match_match_entire_lines_flag(
   pattern = &quot;With loss of Eden, till one greater Man&quot;,
   flags = [&quot;-x&quot;],
   files = [&quot;paradise_lost.txt&quot;],
   expected = [&quot;With loss of Eden, till one greater Man&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_one_match_multiple_flags(
   pattern = &quot;OF ATREUS, Agamemnon, KIng of MEN.&quot;,
   flags = [&quot;-x&quot;, &quot;-i&quot;, &quot;-n&quot;],
   files = [&quot;iliad.txt&quot;],
   expected = [&quot;9:Of Atreus, Agamemnon, King of men.&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_several_matches_no_flags(
   pattern = &quot;may&quot;,
   flags = [],
   files = [&quot;midsummer_night.txt&quot;],
   expected = [
       &quot;Nor how it may concern my modesty,&quot;,
       &quot;But I beseech your grace that I may know&quot;,
       &quot;The worst that may befall me in this case,&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_several_matches_print_line_numbers_flag(
   pattern = &quot;may&quot;,
   flags = [&quot;-n&quot;],
   files = [&quot;midsummer_night.txt&quot;],
   expected = [
       &quot;3:Nor how it may concern my modesty,&quot;,
       &quot;5:But I beseech your grace that I may know&quot;,
       &quot;6:The worst that may befall me in this case,&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_several_matches_match_entire_lines_flag(
   pattern = &quot;may&quot;,
   flags = [&quot;-x&quot;],
   files = [&quot;midsummer_night.txt&quot;],
   expected = []
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_several_matches_caseinsensitive_flag(
   pattern = &quot;ACHILLES&quot;,
   flags = [&quot;-i&quot;],
   files = [&quot;iliad.txt&quot;],
   expected = [
       &quot;Achilles sing, O Goddess! Peleus' son;&quot;,
       &quot;The noble Chief Achilles from the son&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_several_matches_inverted_flag(
   pattern = &quot;Of&quot;,
   flags = [&quot;-v&quot;],
   files = [&quot;paradise_lost.txt&quot;],
   expected = [
       &quot;Brought Death into the World, and all our woe,&quot;,
       &quot;With loss of Eden, till one greater Man&quot;,
       &quot;Restore us, and regain the blissful Seat,&quot;,
       &quot;Sing Heav'nly Muse, that on the secret top&quot;,
       &quot;That Shepherd, who first taught the chosen Seed&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_one_file_no_matches_various_flags(
   pattern = &quot;Gandalf&quot;,
   flags = [&quot;-n&quot;, &quot;-l&quot;, &quot;-x&quot;, &quot;-i&quot;],
   files = [&quot;iliad.txt&quot;],
   expected = []
));

// Test grepping multiples files at once

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_one_match_no_flags(
   pattern = &quot;Agamemnon&quot;,
   flags = [],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [&quot;iliad.txt:Of Atreus, Agamemnon, King of men.&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_several_matches_no_flags(
   pattern = &quot;may&quot;,
   flags = [],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [
       &quot;midsummer_night.txt:Nor how it may concern my modesty,&quot;,
       &quot;midsummer_night.txt:But I beseech your grace that I may know&quot;,
       &quot;midsummer_night.txt:The worst that may befall me in this case,&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_several_matches_print_line_numbers_flag(
   pattern = &quot;that&quot;,
   flags = [&quot;-n&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [
       &quot;midsummer_night.txt:5:But I beseech your grace that I may know&quot;,
       &quot;midsummer_night.txt:6:The worst that may befall me in this case,&quot;,
       &quot;paradise_lost.txt:2:Of that Forbidden Tree, whose mortal tast&quot;,
       &quot;paradise_lost.txt:6:Sing Heav'nly Muse, that on the secret top&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_one_match_print_file_names_flag(
   pattern = &quot;who&quot;,
   flags = [&quot;-l&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [&quot;iliad.txt&quot;, &quot;paradise_lost.txt&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_several_matches_caseinsensitive_flag(
   pattern = &quot;TO&quot;,
   flags = [&quot;-i&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [
       &quot;iliad.txt:Caused to Achaia's host, sent many a soul&quot;,
       &quot;iliad.txt:Illustrious into Ades premature,&quot;,
       &quot;iliad.txt:And Heroes gave (so stood the will of Jove)&quot;,
       &quot;iliad.txt:To dogs and to all ravening fowls a prey,&quot;,
       &quot;midsummer_night.txt:I do entreat your grace to pardon me.&quot;,
       &quot;midsummer_night.txt:In such a presence here to plead my thoughts;&quot;,
       &quot;midsummer_night.txt:If I refuse to wed Demetrius.&quot;,
       &quot;paradise_lost.txt:Brought Death into the World, and all our woe,&quot;,
       &quot;paradise_lost.txt:Restore us, and regain the blissful Seat,&quot;,
       &quot;paradise_lost.txt:Sing Heav'nly Muse, that on the secret top&quot;
   ]
));

set_up_test_case!(
   #[test]
   //#[ignore]
   test_multiple_files_several_matches_caseinsensitive_flag_utf8(
       pattern = &quot;В&quot;, // This letter stands for cyrillic 'Ve' and not latin 'B'. Therefore there should be no matches from paradise_lost.txt
       flags = [&quot;-i&quot;],
       files = [&quot;paradise_lost.txt&quot;, &quot;in_the_white_night.txt&quot;],
       prefix_expected = [
           &quot;in_the_white_night.txt:Выплывает в синеве.&quot;,
           &quot;in_the_white_night.txt:Отражается в Неве.&quot;,
           &quot;in_the_white_night.txt:Мне провидится и снится&quot;,
           &quot;in_the_white_night.txt:В вас ли доброе таится,&quot;
       ]
   )
);

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_several_matches_inverted_flag(
   pattern = &quot;a&quot;,
   flags = [&quot;-v&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [
       &quot;iliad.txt:Achilles sing, O Goddess! Peleus' son;&quot;,
       &quot;iliad.txt:The noble Chief Achilles from the son&quot;,
       &quot;midsummer_night.txt:If I refuse to wed Demetrius.&quot;
   ]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_one_match_match_entire_lines_flag(
   pattern = &quot;But I beseech your grace that I may know&quot;,
   flags = [&quot;-x&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [&quot;midsummer_night.txt:But I beseech your grace that I may know&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_one_match_multiple_flags(
   pattern = &quot;WITH LOSS OF EDEN, TILL ONE GREATER MAN&quot;,
   flags = [&quot;-n&quot;, &quot;-i&quot;, &quot;-x&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   prefix_expected = [&quot;paradise_lost.txt:4:With loss of Eden, till one greater Man&quot;]
));

set_up_test_case!(#[test]
//#[ignore]
test_multiple_files_no_matches_various_flags(
   pattern = &quot;Frodo&quot;,
   flags = [&quot;-n&quot;, &quot;-i&quot;, &quot;-x&quot;, &quot;-l&quot;],
   files = [&quot;iliad.txt&quot;, &quot;midsummer_night.txt&quot;, &quot;paradise_lost.txt&quot;],
   expected = []
));

#}</code></pre></pre>
<a class="header" href="#4-答案" id="4-答案"><h2>4. 答案</h2></a>
<p><details></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
#[macro_use]
extern crate failure;

use failure::Error;
use std::{fs, path::Path};

#[derive(Debug, Fail)]
enum FileAccessError {
   #[fail(display = &quot;File not found: {}&quot;, file_name)]
   FileNotFoundError { file_name: String },

   #[fail(display = &quot;Error reading file: {}&quot;, file_name)]
   FileReadError { file_name: String },
}

pub struct Flags {
   print_line_number: bool,
   print_file_name: bool,
   use_caseinsensitive_comparison: bool,
   use_inverted_comparison: bool,
   match_entire_line: bool,
}

impl Flags {
   pub fn new(flags: &amp;[&amp;str]) -&gt; Self {
       Flags {
           print_line_number: flags.contains(&amp;&quot;-n&quot;),
           print_file_name: flags.contains(&amp;&quot;-l&quot;),
           use_caseinsensitive_comparison: flags.contains(&amp;&quot;-i&quot;),
           use_inverted_comparison: flags.contains(&amp;&quot;-v&quot;),
           match_entire_line: flags.contains(&amp;&quot;-x&quot;),
       }
   }
}

fn get_file_lines(file_name: &amp;str) -&gt; Result&lt;Vec&lt;String&gt;, FileAccessError&gt; {
   let file_path = Path::new(file_name);

   if !file_path.exists() {
       return Err(FileAccessError::FileNotFoundError {
           file_name: String::from(file_name),
       });
   }

   if let Ok(content) = fs::read_to_string(file_path) {
       Ok(content.split(&quot;\n&quot;).map(|line| line.to_string()).collect())
   } else {
       Err(FileAccessError::FileReadError {
           file_name: String::from(file_name),
       })
   }
}

pub fn grep(pattern: &amp;str, flags: &amp;Flags, files: &amp;[&amp;str]) -&gt; Result&lt;Vec&lt;String&gt;, Error&gt; {
   let mut grep_result = vec![];

   let is_multiple_file_search = files.len() &gt; 1;

   for file_name in files {
       let file_lines = get_file_lines(file_name)?;

       grep_result.extend(
           file_lines
               .iter()
               .enumerate()
               .filter(|&amp;(_, line)| {
                   let mut inner_line = String::from(line.clone());

                   let mut inner_pattern = String::from(pattern);

                   if flags.use_caseinsensitive_comparison {
                       inner_line = inner_line.to_lowercase().to_string();

                       inner_pattern = inner_pattern.to_lowercase().to_string();
                   }

                   let mut is_filtered = inner_line.contains(&amp;inner_pattern);

                   if flags.match_entire_line {
                       is_filtered = inner_line == inner_pattern;
                   }

                   if flags.use_inverted_comparison {
                       is_filtered = !inner_line.contains(&amp;inner_pattern);
                   }

                   is_filtered
               })
               .filter(|(_, line)| !line.is_empty())
               .map(|(line_number, line)| {
                   let mut result = line.to_owned();

                   if flags.print_line_number {
                       result.insert_str(0, &amp;format!(&quot;{}:&quot;, line_number + 1));
                   }

                   if is_multiple_file_search {
                       result.insert_str(0, &amp;format!(&quot;{}:&quot;, file_name))
                   }

                   if flags.print_file_name {
                       result = file_name.to_owned().to_owned();
                   }

                   result
               }),
       );
   }

   grep_result.dedup_by(|a, b| (*a).eq(b));

   Ok(grep_result)
}

#}</code></pre></pre>
<p></details></p>
<hr />
<hr />
<a class="header" href="#填充相关" id="填充相关"><h2>填充/相关</h2></a>

                </main>

                <nav class="nav-wrapper" aria-label="Page navigation">
                    <!-- Mobile navigation buttons -->
                    
                    <a rel="prev" href="../poker/README.zh.html" class="mobile-nav-chapters previous" title="Previous chapter"
                        aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                    

                    
                    <a rel="next" href="../scale-generator/README.zh.html" class="mobile-nav-chapters next" title="Next chapter"
                        aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
                    

                    <div style="clear: both"></div>
                </nav>
            </div>
        </div>

        <nav class="nav-wide-wrapper" aria-label="Page navigation">
            
            <a href="../poker/README.zh.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter"
                aria-keyshortcuts="Left">
                <i class="fa fa-angle-left"></i>
            </a>
            

            
            <a href="../scale-generator/README.zh.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter"
                aria-keyshortcuts="Right">
                <i class="fa fa-angle-right"></i>
            </a>
            
        </nav>

    </div>

    

    
    <!-- Google Analytics Tag -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-128555056-1"></script>
    
    <script type="text/javascript">
        var localAddrs = ["localhost", "127.0.0.1", ""];
        if (localAddrs.indexOf(document.location.hostname) === -1) {
            window.dataLayer = window.dataLayer || [];
            function gtag() { dataLayer.push(arguments); }
            gtag('js', new Date());

            gtag('config', 'UA-128555056-1');
        }
    </script>
    

    
    <script src="../ace.js" type="text/javascript" charset="utf-8"></script>
    <script src="../editor.js" type="text/javascript" charset="utf-8"></script>
    <script src="../mode-rust.js" type="text/javascript" charset="utf-8"></script>
    <script src="../theme-dawn.js" type="text/javascript" charset="utf-8"></script>
    <script src="../theme-tomorrow_night.js" type="text/javascript" charset="utf-8"></script>
    

    
    <script src="../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="../mark.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="../searcher.js" type="text/javascript" charset="utf-8"></script>
    

    <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
    <script src="../book.js" type="text/javascript" charset="utf-8"></script>

    <!-- Custom JS scripts -->
    

    

</body>

</html>